package cn.edu.sjtu.se.dslab.component.data.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.component.data.EntityDiagram;
import cn.edu.sjtu.se.dslab.service.IDiagramService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.util.Const;

public class DiagramXmlParser {
	private final static String UML_DIAGRAM = "umldiagrams";
	private final static String UML_CLASS_DIAGRAM = "UMLClassDiagram";
	private final static String UML_CLASS = "UMLClass";

	private final static String UML_AGGREGATION = "UMLAggregation";
	private final static String UML_GENERALIZATION = "UMLGeneralization";
	private final static String UML_DEPENDENCY = "UMLDependency";

	private final static String SIDE_A = "side_A";
	private final static String SIDE_B = "side_B";
	private final static String SUPER_ITEM = "superitem";

	private final static String ITEM = "item";
	private final static String ID = "id";
	private final static String VALUE = "value";
	private final static String BACKGROUND_COLOR = "backgroundColor";
	private final static String NAME = "name";
	private final static String BACK_GROUND_NODES = "backgroundNodes";
	private final static String X = "x";
	private final static String Y = "y";
	private final static String WIDTH = "width";
	private final static String HEIGHT = "height";
	private final static String LINE_COLOR = "lineColor";
	private final static String LINE_WIDTH = "lineWidth";
	private final static String TAG_VALUES = "tagValues";
	private final static String VISIBLE_SUB_COMPONENTS = "visibleSubComponents";

	private final static String ATTRIBUTES = "attributes";
	private final static String OPERATIONS = "operations";

	public String highLightEntity(String content, String entityName) {
		try {
			Document document = DocumentHelper.parseText(content);
			Element rootElm = document.getRootElement();
			Element classElm;
			if (rootElm.getName().equals(UML_DIAGRAM)) {
				classElm = rootElm.element(UML_CLASS_DIAGRAM);
			} else if (rootElm.getName().equals(UML_CLASS_DIAGRAM)) {
				classElm = rootElm;
			} else {
				return content;
			}
			List<Element> nodes = classElm.elements(UML_CLASS);
			for (Iterator it = nodes.iterator(); it.hasNext();) {
				Element elm = (Element) it.next();
				List<Element> items = elm.elements(ITEM);
				for (int i = 0; i < items.size(); i++) {
					if (items.get(i).attribute(ID).getText().equals(NAME)
							&& items.get(i).attribute(VALUE).getText()
									.equals(entityName)) {
						elm.attribute(BACKGROUND_COLOR).setText(
								Const.COLOR_HIGHLIGHT);
						break;
					}
				}
			}
			return document.asXML();
		} catch (Exception e) {
			// TODO: handle exception
		}

		return content;
	}

	public String parseDataEntity2Diagram(DomainEntity entity) {
		// 使用DocumentHelper.createDocument方法建立一个文档实例
		Document document = DocumentHelper.createDocument();
		// 使用addElement方法方法创建根元素
		Element catalogElement = document.addElement(UML_DIAGRAM);

		// 使用addElement方法向UML_DIAGRAM元素添加UML_CLASS_DIAGRAM子元素
		Element classDiagramElement = catalogElement
				.addElement(UML_CLASS_DIAGRAM);
		// 使用addAttribute方法向UML_CLASS_DIAGRAM元素添加name和backgroundNodes属性
		classDiagramElement.addAttribute(NAME, "Class diagram");
		classDiagramElement.addAttribute(BACK_GROUND_NODES, "#ffffbb");

		// 使用addElement方法向classDiagramElement元素添加UMLclass子元素
		Element classElement = classDiagramElement.addElement(UML_CLASS);
		// 使用addAttribute方法向classElement元素添加属性
		classElement.addAttribute(ID, "" + entity.getId());
		classElement.addAttribute(X, "100");
		classElement.addAttribute(Y, "100");
		classElement.addAttribute(WIDTH, Const.DIAGRAM_WIDTH);
		classElement.addAttribute(HEIGHT, Const.DIAGRAM_HEIGHT);
		classElement.addAttribute(BACKGROUND_COLOR, Const.COLOR_HIGHLIGHT);
		classElement.addAttribute(LINE_COLOR, Const.COLOR_LINE_COLOR);
		classElement.addAttribute(LINE_WIDTH, Const.LINE_WIDTH);
		classElement.addAttribute(TAG_VALUES, "");

		// 使用addElement方法向classElement元素添加nameItem子元素
		Element nameItem = classElement.addElement(ITEM);
		nameItem.addAttribute(ID, NAME);
		nameItem.addAttribute(VALUE, entity.getName());

		// 使用addElement方法向classElement元素添加attributeElement子元素
		Element attributeElement = classElement.addElement(SUPER_ITEM);
		attributeElement.addAttribute(ID, ATTRIBUTES);
		attributeElement.addAttribute(VISIBLE_SUB_COMPONENTS, "false");

		// 使用addElement方法向nameElement元素添加attributeItem子元素
		Element attributeItem = attributeElement.addElement(ITEM);
		attributeItem.addAttribute(VALUE, "uri=" + entity.getUri());

		// 使用addElement方法向classElement元素添加operationElement子元素
		Element operationElement = classElement.addElement(SUPER_ITEM);
		operationElement.addAttribute(ID, OPERATIONS);
		operationElement.addAttribute(VISIBLE_SUB_COMPONENTS, "false");

		return document.asXML().replace("\n", "");
	}

	private void addEntityToDiagram(Element classDiagramElement,
			DomainEntity entity, int x, int y) {
		// 使用addElement方法向classDiagramElement元素添加UMLclass子元素
		Element classElement = classDiagramElement.addElement(UML_CLASS);
		// 使用addAttribute方法向classElement元素添加属性
		classElement.addAttribute(ID, "" + entity.getId());
		classElement.addAttribute(X, "" + x);
		classElement.addAttribute(Y, "" + y);
		classElement.addAttribute(WIDTH, Const.DIAGRAM_WIDTH);
		classElement.addAttribute(HEIGHT, Const.DIAGRAM_HEIGHT);
		if (entity.getType().endsWith(Const.DATA_TYPE)) {
			classElement.addAttribute(BACKGROUND_COLOR, Const.COLOR_DATA_TYPE);
		} else if (entity.getType().endsWith(Const.AVIONICS_EQUIPMENT)) {
			classElement.addAttribute(BACKGROUND_COLOR,
					Const.COLOR_AVIONICS_EQUIPMENT);
		} else {
			classElement
					.addAttribute(BACKGROUND_COLOR, Const.COLOR_DATA_ENTITY);
		}
		classElement.addAttribute(LINE_COLOR, Const.COLOR_LINE_COLOR);
		classElement.addAttribute(LINE_WIDTH, Const.LINE_WIDTH);
		classElement.addAttribute(TAG_VALUES, "");

		// 使用addElement方法向classElement元素添加nameItem子元素
		Element nameItem = classElement.addElement(ITEM);
		nameItem.addAttribute(ID, NAME);
		nameItem.addAttribute(VALUE, entity.getName());

		// 使用addElement方法向classElement元素添加attributeElement子元素
		Element attributeElement = classElement.addElement(SUPER_ITEM);
		attributeElement.addAttribute(ID, ATTRIBUTES);
		attributeElement.addAttribute(VISIBLE_SUB_COMPONENTS, "false");

		// 使用addElement方法向nameElement元素添加attributeItem子元素
		Element attributeItem = attributeElement.addElement(ITEM);
		attributeItem.addAttribute(VALUE, "uri=" + entity.getUri());

		// 使用addElement方法向classElement元素添加operationElement子元素
		Element operationElement = classElement.addElement(SUPER_ITEM);
		operationElement.addAttribute(ID, "operations");
		operationElement.addAttribute(VISIBLE_SUB_COMPONENTS, "false");
	}

	public String addNewConnection(String currentdiagram,
			Set<DomainEntity> entities) {
		Set<String> uriList = new HashSet<String>();
		try {
			Document document = DocumentHelper.parseText(currentdiagram);
			Element rootElm = document.getRootElement();
			Element classElm;
			if (rootElm.getName().equals(UML_DIAGRAM)) {
				classElm = rootElm.element(UML_CLASS_DIAGRAM);
			} else if (rootElm.getName().equals(UML_CLASS_DIAGRAM)) {
				classElm = rootElm;
			} else {
				return currentdiagram;
			}

			List<Element> nodes = classElm.elements(UML_CLASS);
			// 计算已有class
			for (Iterator it = nodes.iterator(); it.hasNext();) {
				Element elm = (Element) it.next();
				List<Element> superItems = elm.elements(SUPER_ITEM);
				if (superItems != null) {
					for (int i = 0; i < superItems.size(); i++) {
						if (superItems.get(i).attribute(ID).getText()
								.equals(ATTRIBUTES)) { // 属性superitem
							List<Element> items = superItems.get(i).elements(
									ITEM);
							if (items != null) {
								for (int j = 0; j < items.size(); j++) {
									String value = items.get(j)
											.attribute(VALUE).getText();

									if (value.startsWith("uri=")) {
										System.out.println("uri:"
												+ value.substring(
														value.indexOf("=") + 1,
														value.length()));
										uriList.add(value.substring(
												value.indexOf("=") + 1,
												value.length()));
										break;
									}
								}
							}
						}
					}
				}

			}
			if (entities != null) {
				int xStart = 100;
				int yStart = 100;
				for (DomainEntity entity : entities) {
					if (!uriList.contains(entity.getUri())) {
						uriList.add(entity.getUri());
						Random random = new Random();
						xStart = random.nextInt(500);
						yStart = random.nextInt(500);
						addEntityToDiagram(classElm, entity, xStart, yStart);
					}
				}
			}
			return document.asXML();
		} catch (Exception e) {
			// TODO: handle exception
		}
		return currentdiagram;
	}

	public void createDiagram(DomainEntity baseEntity,
			IDomainEntityService domainEntityService,EntityDiagram diagram,String currentdiagram) {
		try {
				Document document;
				Element rootElm;
				Element classElm;
				//首先检测xml string是否能够正常解析，如果不能直接退出
				try {
					document = DocumentHelper.parseText(currentdiagram);
					rootElm = document.getRootElement();
					if (rootElm.getName().equals(UML_DIAGRAM)) {
						classElm = rootElm.element(UML_CLASS_DIAGRAM);
					} else if (rootElm.getName().equals(UML_CLASS_DIAGRAM)) {
						classElm = rootElm;
					} else {
						return;
					}
				} catch (DocumentException e) {
					// TODO: handle exception
					e.printStackTrace();
					return;
				}
				//确定diagram可以正常保存
				//EntityDiagram diagram = new EntityDiagram();
				long formerdiagId = 0;
				if (baseEntity.getDiagram()!= null) {
					formerdiagId = baseEntity.getDiagram().getId();
					System.out.println("former:"+formerdiagId);
				}
//				try {
//					String file = baseEntity.getUri().split(":")[baseEntity
//						.getUri().split(":").length - 1] + "/diagram.xml";
//					String realPath = Const.ABSOLUTE_DIAGRAM_PATH + file;
//					System.out.println("realPath:" + realPath);
//					FileWriter fWriter = null;
//					File writeFile = getFile(realPath);
//					fWriter = new FileWriter(writeFile);
//					fWriter.write(currentdiagram);
//					fWriter.flush();
//					fWriter.close();
//					diagram.setFilepath(file);
//					diagramService.addDiagram(diagram);
				baseEntity.setDiagram(diagram);
				domainEntityService.updateDomainEntity(baseEntity);
//				} catch (IOException e) {
//					// TODO: handle exception
//					e.printStackTrace();
//					diagram = null;
//				}

			Map<String, DomainEntity> map = new HashMap<String, DomainEntity>();
			List<Element> nodes = classElm.elements(UML_CLASS);
			// 计算已有class
			for (Iterator it = nodes.iterator(); it.hasNext();) {
				Element elm = (Element) it.next();
				// 类 ID
				String classId = elm.attribute(ID).getText();
				List<Element> superItems = elm.elements(SUPER_ITEM);
				if (superItems != null) {
					for (int i = 0; i < superItems.size(); i++) {
						if (superItems.get(i).attribute(ID).getText()
								.equals(ATTRIBUTES)) { // 属性superitem
							List<Element> items = superItems.get(i).elements(
									ITEM);
							if (items != null) {
								for (int j = 0; j < items.size(); j++) {
									String value = items.get(j)
											.attribute(VALUE).getText();
									//System.out.println("uri:" + value);
									if (value.startsWith("uri=")) {
										String uri = value.substring(
												value.indexOf("=") + 1,
												value.length());
										DomainEntity entity = domainEntityService
												.getDomainEntityByUri(uri);
										if (entity.getDiagram() != null && entity.getDiagram().getId() == diagram.getId()) {
											
										}else if (entity.getDiagram() == null
												&& diagram != null) {
											entity.setDiagram(diagram);
											domainEntityService
													.updateDomainEntity(entity);
										}else if ((entity.getDiagram() != null )&&(entity.getDiagram().getId() == formerdiagId)) {
											entity.setDiagram(diagram);
											domainEntityService
													.updateDomainEntity(entity);
										}
										map.put(classId, entity);
										break;
									}
								}
							}
						}
					}
				}

			}
			// 计算generalization
			List<Element> generElements = classElm.elements(UML_GENERALIZATION);
			if (generElements != null) {
				for (int i = 0; i < generElements.size(); i++) {
					String child = generElements.get(i).attribute(SIDE_A)
							.getText().toString().trim();
					String parent = generElements.get(i).attribute(SIDE_B)
							.getText().toString().trim();// 被继承
					DomainEntity childEntity = map.get(child);
					DomainEntity parentEntity = map.get(parent);
					if (parentEntity.getExtendsSet() != null) {
						for (DomainEntity entity: parentEntity.getExtendsSet()) {
							if (entity.getId() == childEntity.getId()) {
								parentEntity.getExtendsSet().remove(entity);
								domainEntityService.updateDomainEntity(parentEntity);
								System.out.println("update child");
								break;
							}
						}
					}
					if (childEntity.getExtendsSet() != null) {
						childEntity.getExtendsSet().add(parentEntity);
					} else {
						Set<DomainEntity> extendSet = new HashSet<DomainEntity>();
						extendSet.add(parentEntity);
						childEntity.setExtendsSet(extendSet);
					}
					domainEntityService.updateDomainEntity(childEntity);
				}
			}
			// 计算Dependency
			List<Element> dependElements = classElm.elements(UML_DEPENDENCY);
			if (dependElements != null) {
				for (int i = 0; i < dependElements.size(); i++) {
					String child = dependElements.get(i).attribute(SIDE_A)
							.getText().toString().trim(); // 依赖
					String parent = dependElements.get(i).attribute(SIDE_B)
							.getText().toString().trim(); // 被依赖
					DomainEntity childEntity = map.get(child);
					DomainEntity parentEntity = map.get(parent);
					if (childEntity.getDepends() != null) {
						childEntity.getDepends().add(parentEntity);
					} else {
						Set<DomainEntity> dependSet = new HashSet<DomainEntity>();
						dependSet.add(parentEntity);
						childEntity.setDepends(dependSet);
					}
					domainEntityService.updateDomainEntity(childEntity);
				}
			}
			// 计算Aggregation
			List<Element> aggrElements = classElm.elements(UML_AGGREGATION);
			if (aggrElements != null) {
				for (int i = 0; i < aggrElements.size(); i++) {
					String child = aggrElements.get(i).attribute(SIDE_A)
							.getText().toString().trim();// 包含
					String parent = aggrElements.get(i).attribute(SIDE_B)
							.getText().toString().trim();// 被包含

					DomainEntity childEntity = map.get(child);
					DomainEntity parentEntity = map.get(parent);
					if (childEntity.getAggregations() != null) {
						childEntity.getAggregations().add(parentEntity);
					} else {
						Set<DomainEntity> aggrSet = new HashSet<DomainEntity>();
						aggrSet.add(parentEntity);
						childEntity.setAggregations(aggrSet);
					}
					domainEntityService.updateDomainEntity(childEntity);
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	protected File getFile(String targetFileName) throws IOException {
		File targetFile = new File(targetFileName);
		if (!targetFile.getParentFile().exists()) {
			targetFile.getParentFile().mkdirs();
		}
		if (!targetFile.exists()) {
			targetFile.createNewFile();
		}
		return targetFile;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// String
		// str="<umldiagrams><UMLClassDiagram name=\"Class diagram\" backgroundNodes=\"#9cfda3\"><UMLClass id=\"UMLClass_1\" x=\"435\" y=\"268\" width=\"78\" height=\"40\" backgroundColor=\"#9cfda3\" lineColor=\"#294253\" lineWidth=\"1\" tagValues=\"\"><superitem id=\"stereotypes\" visibleSubComponents=\"true\"/><item id=\"name\" value=\"ClassName1\"/><superitem id=\"attributes\" visibleSubComponents=\"true\"/><superitem id=\"operations\" visibleSubComponents=\"true\"/></UMLClass><UMLClass id=\"UMLClass_0\" x=\"221\" y=\"252\" width=\"78\" height=\"40\" backgroundColor=\"#ffffbb\" lineColor=\"#294253\" lineWidth=\"1\" tagValues=\"\"><superitem id=\"stereotypes\" visibleSubComponents=\"true\"/><item id=\"name\" value=\"ClassName\"/><superitem id=\"attributes\" visibleSubComponents=\"true\"/><superitem id=\"operations\" visibleSubComponents=\"true\"/></UMLClass><UMLGeneralization id=\"UMLGeneralization_0\" side_A=\"UMLClass_0\" side_B=\"UMLClass_1\"><point x=\"299\" y=\"274.9158878504673\"/><point x=\"435\" y=\"285.0841121495327\"/><superitem id=\"stereotype\" visibleSubComponents=\"true\"/><item id=\"name\" value=\"\"/></UMLGeneralization></UMLClassDiagram></umldiagrams>";
		// DiagramXmlParser parser = new DiagramXmlParser();
		// System.out.print(parser.highLightEntity(str, "ClassName"));
		DiagramXmlParser parser = new DiagramXmlParser();
		DomainEntity entity = new DomainEntity();
		entity.setId(1);
		entity.setUri("domain_entity:data:12367890");
		entity.setName("FlightPoint");
		System.out.println(parser.parseDataEntity2Diagram(entity));

	}
}
